package com.cjc.express.serviceImpl;


import com.cjc.express.entity.*;
import com.cjc.express.exception.ImportException;
import com.cjc.express.exception.ValidationException;
import com.cjc.express.mapper.CompanyMapper;
import com.cjc.express.mapper.PriceMapper;
import com.cjc.express.service.AdminService;
import com.cjc.express.utils.ExcelImportUtils;
import com.cjc.express.utils.ExpressUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.cjc.express.utils.ExpressUtils.isChinese;
import static com.cjc.express.utils.ExpressUtils.isLegalDestName;
import static com.cjc.express.utils.ExpressUtils.processPDestString;

/**
 * ====================
 * Created with intellij IDEA
 * 创建者：杜一平
 * 日期：2017/1/19（星期五）
 * 时间：08：00
 * 说明：该类重写管理员服务层接口的方法，用于具体实现管理的相关操作
 */

@Service(value = "adminService")
public class AdminServiceImpl implements AdminService {
    // 自动装配管理员映射层
    @Autowired
    private CompanyMapper companyMapper;

    // 自动装配报价表映射层
    @Autowired
    private PriceMapper priceMapper;

    // 实例化快递公司表
    Company company = new Company();
    // 实例化报价表
    Price price = new Price();


    /**
     * 查询所有公司
     * @return List<Company>
     */
    @Override
    public List<Company> listallcompany() {
        try {

            List<Company> companies = companyMapper.selectAllCompany();
            if (companies.isEmpty()) {
                throw new ValidationException("暂无相关记录，工作人员正在赶来的路上!");
            }
            return companies;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 添加公司
     * @param companyname 公司名字
     * @return CompanyJsons 公司json组合
     */
    @Override
    public CompanyJsons insertCompany(String companyname) {
        try {
            // 字段不合法
            if (ExpressUtils.JudgeNull(companyname) || companyname.length() > 8) {
                return StaticCompanyJsons.companyJsons1;
            }
            Company companies = companyMapper.selectByCompanyName(companyname);
            if (null != companies) {
                // 已有此快递公司
                return new CompanyJsons(1001, "已有此快递公司，请勿重复添加!");
            } else {
                // 插入
                company.addCompanyId(ExpressUtils.getUuid())
                        .addCompanyname(companyname);
                companyMapper.insertSelective(company);
                // 返回状态成功
                return StaticCompanyJsons.companyJsons0;
            }
        } catch (Exception e) {
            throw e;
        }

    }

    /**
     * 更新公司
     * @param company 公司对象
     * @return CompanyJsons 公司json组合
     */
    @Override
    public CompanyJsons updateByPrimaryKeySelective(Company company) {
        try {
            // 判断快递公司对象是否合法
            if (ExpressUtils.CheckCompany(company)) {
                return StaticCompanyJsons.companyJsons1;
            }
            Company company1 = companyMapper.selectByCompanyName(company.getCompanyname());
            if (null != company1) {
                // 快递公司已存在情况
                return new CompanyJsons(1001, "已有此快递公司，请勿重复添加!");
            }
            // 修改快递公司名字
            if (companyMapper.updateByPrimaryKeySelective(company) == 1) {
                // 更新报价表
                price.addCompanyid(company.getCompanyid())
                        .addCompanyname(company.getCompanyname());
                priceMapper.updateByCompanyIdSelective(price);
                // 返回状态成功
                return StaticCompanyJsons.companyJsons0;
            } else {
                return StaticCompanyJsons.companyJsons1;
            }

        } catch (Exception e) {
            throw e;
        }
    }


    /**
     * 删除公司
     * @param companyid 公司id
     * @return CompanyJsons 公司json组合
     */
    @Override
    public CompanyJsons deleteByPrimaryKey(String companyid) {
        try {
            // 判断字段是否合法
            if (ExpressUtils.JudgeNull(companyid) || companyid.length() > 36) {
                return StaticCompanyJsons.companyJsons1;
            }
            // 执行相关操作
            if (companyMapper.deleteByPrimaryKey(companyid) == 1) {
                price.setCompanyid(companyid);
                // 一句公司id删除报价表
                priceMapper.deleteByCompanyid(price);
                return StaticCompanyJsons.companyJsons0;
            } else {
                // 没有这个id的情况
                return StaticCompanyJsons.companyJsons1;
            }
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     * 查询所有报价表
     * @param pageNum 页数
     * @param pageSize 数目
     * @return Page<Price> 可分页报价表
     */
    @Override
    public Page<Price> selectAllPrice(Integer pageNum, Integer pageSize) {
        try {
            if (null == pageNum || null == pageSize || pageNum.toString().length() > 3
                    || pageSize.toString().length() > 3
                    || pageNum == 0 || pageSize == 0) {
                pageNum = 1;
                pageSize = 10;
            }
            PageHelper.startPage(pageNum, pageSize);
            Page<Price> prices = priceMapper.selectAllPrice();
            if (prices.isEmpty()) {
                throw new ValidationException("暂无相关记录，工作人员正在赶来的路上!");
            }
            return prices;
        } catch (Exception e) {
            throw e;
        }

    }

    /**
     * 添加报价表
     * @param price 报价表对象
     * @return PriceJsons 报价表json组合
     */
    @Override
    public PriceJsons insertSelective(Price price) {
        try {
            // 检查价格表字段是否合法
            if (ExpressUtils.CheckPrice(price)) {
                return StaticPriceJsons.priceJsons1;
            }
            // 获取快递公司表列表
            Company tc = companyMapper.selectByCompanyName(price.getCompanyname());
            // 检查快递公司表中快递公司是否存在
            if (ExpressUtils.isEmpty(tc)) {
                return new PriceJsons(1001, "快递公司不存在!");
            }
            // 查询报价是否存在
            Price tp = priceMapper.findPrice(price.getCompanyname(), price.getPricedest());
            if (ExpressUtils.isEmpty(tp)) {
                // 报价不存在，插入
                price.setPriceid(ExpressUtils.getUuid()); // 设置uuid
                price.setPriceorigin("厦门");
                price.setCompanyid(tc.getCompanyid());
                // 执行插入操作
                priceMapper.insertSelective(price);
                return StaticPriceJsons.priceJsons0;
            }
            // 报价表存在
            return new PriceJsons(1001, "已有此线路!");
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 更新报价表
     * @param price 报价表对象
     * @return PriceJsons 报价表json组合
     */
    @Override
    public PriceJsons updateByPrimaryKeySelective(Price price) {
        try {
            // 字段是否合法
            if (ExpressUtils.CheckPrice(price) || ExpressUtils.JudgeNull(price.getPriceid())
                    || price.getPriceid().length() > 36) {
                return StaticPriceJsons.priceJsons1;
            }
            // 获取快递公司表列表
            Company tc = companyMapper.selectByCompanyName(price.getCompanyname());
            // 检查快递公司表中快递公司是否存在
            if (ExpressUtils.isEmpty(tc)) {
                return new PriceJsons(1001, "快递公司不存在");
            }

            // 查询报价表是否有这条线路
            Price price1 = priceMapper.selectByCompanyAndDest1(price.getCompanyname(), price.getPricedest());
            if (null == price1) {
                price.setCompanyid(tc.getCompanyid());
                // 没有这条线路，执行修改
                if (priceMapper.updateByPrimaryKeySelective(price) == 1) {
                    return StaticPriceJsons.priceJsons0;
                }
                return StaticPriceJsons.priceJsons1;
            }

            // 有判断id是否是同一id
            if (price1.getPriceid().equals(price.getPriceid())) {
                // 同一条记录不存在收件地与快递公司的组合冲突
                // 判断是否修改价格
                if (price1.getPriceinitweight().equals(price.getPriceinitweight()) &&
                        price1.getPriceoverweight().equals(price.getPriceoverweight())) {
                    return new PriceJsons(1001, "您未修改任何信息!");
                }
                // 执行更新操作
                price.setCompanyid(tc.getCompanyid());
                price.setPriceorigin("厦门");
                int i = priceMapper.updateByPrimaryKeySelective(price);
                if (i == 1) {
                    // 操作成功
                    return StaticPriceJsons.priceJsons0;
                }
                return StaticPriceJsons.priceJsons1;

            } else {
                // 线路冲突
                return new PriceJsons(1001, "已有此线路!");
            }
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     * 删除报价表
     * @param priceid 报价表id
     * @return PriceJsons 报价表json组合
     */
    @Override
    public PriceJsons deleteByPriceId(String priceid) {
        try {
            // 检查字段是否合法
            if (ExpressUtils.JudgeNull(priceid) || priceid.length() > 36) {
                return StaticPriceJsons.priceJsons1;
            }
            // 判断删除是否成功
            if (priceMapper.deleteByPrimaryKey(priceid) == 1) {
                return StaticPriceJsons.priceJsons0;
            } else {
                // 失败
                return StaticPriceJsons.priceJsons1;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 依据公司名字以及收件地并查询
     * @param companyname 公司
     * @param dest 收件地
     * @param pageNum 页数
     * @param pageSize 数目
     * @return Page<Price> 可分页报价表
     */
    @Override
    public Page<Price> selectByCompanyAndDest(String companyname, String dest
            , Integer pageNum, Integer pageSize) {
        try {
            // 判断字段是否合法
            if (ExpressUtils.JudgeNull(companyname) || ExpressUtils.JudgeNull(dest)
                    || companyname.length() > 8 || dest.length() > 20) {
                throw new ValidationException("亲，您的输入有误，请重新输入!");
            }
            if (null == pageNum || null == pageSize || pageNum.toString().length() > 3
                    || pageSize.toString().length() > 3 || pageNum == 0 || pageSize == 0) {
                pageNum = 1;
                pageSize = 10;
            }
            PageHelper.startPage(pageNum, pageSize);
            Page<Price> prices = priceMapper.selectByCompanyAndDest(companyname, dest);
            if (prices.isEmpty()) {
                // 表内无数据
                throw new ValidationException("暂无相关记录，工作人员正在赶来的路上!");
            } else {
                // 成功
                return prices;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 依据收件地查询
     * @param dest 收件地
     * @param pageNum 页数
     * @param pageSize 数目
     * @return Page<Price> 可分页报价表
     */
    @Override
    public Page<Price> selectByDest(String dest, Integer pageNum, Integer pageSize) {
        try {
            // 判断输入是否合法
            if (dest == null || dest.trim().isEmpty() || dest.length() > 20) {
                throw new ValidationException("亲，您的输入有误，请重新输入!");
            }
            if (null == pageNum || null == pageSize || pageNum.toString().length() > 3
                    || pageSize.toString().length() > 3 || pageNum == 0 || pageSize == 0) {
                pageNum = 1;
                pageSize = 10;
            }
            // 获取相关记录
            PageHelper.startPage(pageNum, pageSize);
            Page<Price> prices = priceMapper.selectByDest(dest);
            if (null != prices && !prices.isEmpty()) {
                // 成功
                return prices;
            } else {
                // 无数据情况
                throw new ValidationException("暂无相关记录，工作人员正在赶来的路上!");
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 依据公司查找
     * @param companyname 公司名字
     * @param pageNum 页数
     * @param pageSize 数目
     * @return Page<Price> 可以分页报价表
     */
    @Override
    public Page<Price> selectByCompany(String companyname, Integer pageNum, Integer pageSize) {
        try {
            // 判断字段是否合法
            if (companyname == null || companyname.length() <= 0 || companyname.length() > 8)
                throw new ValidationException("亲，您的输入有误，请重新输入!");
            if (null == pageNum || null == pageSize || pageNum.toString().length() > 3
                    || pageSize.toString().length() > 3 || pageNum == 0 || pageSize == 0) {
                pageNum = 1;
                pageSize = 10;
            }
            // 获取相关记录
            PageHelper.startPage(pageNum, pageSize);
            // 获取查询数据
            Page<Price> prices = priceMapper.selectByCompany(companyname);
            if (prices.isEmpty()) {
                // 无数据情况
                throw new ValidationException("暂无相关记录，工作人员正在赶来的路上!");
            } else {
                // 查询成功
                return prices;
            }
        } catch (Exception e) {
            throw e;
        }
    }


    // @author：hjj @描述：通过快递公司名称、寄件地和收件地查询报价表中的一条记录
    @Override
    public Price findPrice(String companyname, String pricedest) {
        return priceMapper.findPrice(companyname, pricedest);
    }

    /**
     * @param fileName 文件名
     * @param mfile
     * @return
     * @创建时间 2018年1月20日12:30:17
     * @描述 将excel表导入数据库
     * @author hjj
     */
    @Override
    public String executeImportExcel(MultipartFile mfile) {

        // 获取文件内容大小
        long size = mfile.getSize();
        // 获取文件名
        String fileName = mfile.getOriginalFilename();

        if (StringUtils.isEmpty(fileName)) {
            // 如果未选择文件
            throw new ImportException("未选择文件");
        }

        if (!ExpressUtils.validateExcel(fileName)) {
            // 验证文件名不合格
            throw new ImportException("不是excel文件");
        }

        if (size == 0) {
            // 判断文件内容是否为空
            throw new ImportException("文件内容为空");
        }

        //创建一个目录 （它的路径名由当前 File 对象指定，包括任一必须的父路径。）
        File uploadDir = new File("./temp/");
        if (!uploadDir.exists()) uploadDir.mkdirs();

        //新建一个文件
        File tempFile = new File("./temp/" + new Date().getTime() + ".xlsx");

        //初始化输入流
        InputStream is = null;

        try {
            File absoluteTempFile = tempFile.getAbsoluteFile();
            //将上传的文件写入新建的文件中
            mfile.transferTo(absoluteTempFile);
            //根据新建的文件实例化输入流
            is = new FileInputStream(tempFile);
            //根据版本选择创建Workbook的方式
            Workbook wb;
            //根据文件名判断文件是2003版本还是2007版本
            if (ExpressUtils.isExcel2007(fileName)) {
                wb = new XSSFWorkbook(is);
            } else {
                wb = new HSSFWorkbook(is);
            }

            return readExcelValue(wb, absoluteTempFile);

        } catch (ImportException ie) {
            throw ie ;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    is = null;
                    e.printStackTrace();
                }
            }
        }

        throw new ImportException("导入出错! 请检查Excel表中数据!");
    }

    /**
     * @param wb
     * @return
     * @创建时间 2018年1月20日12:38:41
     * @描述 解析Excel里面的数据
     * @author hjj
     */
    private String readExcelValue(Workbook wb, File tempFile) {

        // 换行符
        String br = "<br/>";
        // 错误信息接收器
        String errorMsg = "";
        // 得到第一个shell
        Sheet sheet = wb.getSheetAt(0);
        // 得到Excel的行数
        int totalRows = sheet.getPhysicalNumberOfRows();
        // 第一行为标题，不读取
        if (totalRows == 1 || totalRows == 0) {
            errorMsg += br + "Excel表中没有可用数据;";
        }
        // 总列数
        int totalCells = 0;
        // 得到Excel的列数(前提是有行数)，从第二行算起
        if (totalRows > 1 && null != sheet.getRow(1)) {
            totalCells = sheet.getRow(1).getPhysicalNumberOfCells();
        }

        // 存放从Excel中获取的数据到列表中
        List<Price> pricesList = new ArrayList<Price>();
        // 临时保存Excel表中的一条信息
        Price tempPrice;
        // 循环Excel行数,从第二行开始, 标题不入库
        for (int r = 1; r < totalRows; r++) {
            // 记录次行的错误信息
            String rowMessage = "";
            // 获得表格中一行数据
            Row row = sheet.getRow(r);
            if (row == null) {
                // 如果此行数据为空，开始读取下一行
                errorMsg += br + "第" + (r + 1) + "行数据有问题，请仔细检查!";
                continue;
            }

            tempPrice = new Price();
            // 设置快递价格记录的id
            tempPrice.setPriceid(ExpressUtils.getUuid());
            // 快递公司名称
            String cName = "";
            // 寄件地
            String pOrigin = "";
            // 目的地
            String pDest = "";
            // 首重价格
            BigDecimal pInitWeight;
            // 续重价格
            BigDecimal pOverWeight;

            // 循环Excel的列
            for (int c = 0; c < totalCells; c++) {
                // 获取r+1行第c+1列的数据
                Cell cell = row.getCell(c);

                if (null != cell) {

                    cell.setCellType(Cell.CELL_TYPE_STRING);
                    String cellValue = cell.getStringCellValue().trim();

                    if (c == 0) {
                        // 第一列，快递公司名称
                        cName = cellValue;
                        if (StringUtils.isEmpty(cName)) {
                            // 如果快递公司名称为空，直接读取下一行
                            rowMessage += "快递公司名称不能为空；";
                            break;
                        } else if (cName.length() > 8) {
                            // 如果快递公司名称超过8个字，直接读取下一行
                            rowMessage += "快递公司的名字不能超过8个字；";
                            break;
                        } else {
                            // 如果快递公司名字合法；
                            // 按照名称在快递公司表张查询快递公司是否存在
                            Company tc = companyMapper.selectByCompanyName(cName);
                            if (ExpressUtils.isEmpty(tc)) {
                                // 快递公司不存在
                                rowMessage += "快递公司不存在，请先添加；";
                                break;
                            } else {
                                // 在报价表中，设置公司的id和名称
                                tempPrice.setCompanyid(tc.getCompanyid());
                                tempPrice.setCompanyname(cName);
                            }
                        }
                    } else if (c == 1) {
                        // 第二列，寄件地
                        pOrigin = cell.getStringCellValue().trim();
                        if (StringUtils.isEmpty(pOrigin)) {
                            // 如果寄件地为空
                            rowMessage += "寄件地不能为空；";
                        } else if (!pOrigin.equals("厦门")) {
                            // 寄件地必须是厦门，不是厦门，提示错误，并继续读取下一行
                            rowMessage += "寄件地必须为厦门;";
                            break;
                        } else {
                            tempPrice.setPriceorigin(pOrigin);
                        }
                    } else if (c == 2) {
                        // 第三列，收件的
                        pDest = cellValue;
                        if (StringUtils.isEmpty(pDest)) {
                            // 如果收件的为空
                            rowMessage += "收件地不能为空；";
                        } else if (pDest.length() > 20) {
                            // 字数大于20
                            rowMessage += "收件地的名称不能超过20个字；";
                        }else if(!isChinese(pDest)){
                            rowMessage += "收件地不能包含英文字符;";
                        } else if (!isLegalDestName(pDest)){
                            rowMessage += "请按规则填写收件地名称(如:福建/厦门、北京)";
                        }else {
                            pDest = processPDestString(pDest);
                            // 按照快递公司名字和收件地查询记录是否存在
                            Price tp = findPrice(cName, pDest);
                            if (null != tp) {
                                // 已存在
                                rowMessage += "线路已存在, 如需修改请点击编辑；";
                            } else {
                                // 不存在，设置收件地
                                tempPrice.setPricedest(pDest);
                            }
                        }
                    } else if (c == 3) {
                        // 第四列，首重价格
                        String piw = cellValue;

                        if (StringUtils.isEmpty(piw)) {
                            rowMessage += "首重价格不能为空";
                        } else if (!ExpressUtils.isNumeric(piw) || piw.length() > 4) {
                            rowMessage += "首重价格必须是4位正整数";
                        } else {
                            pInitWeight = new BigDecimal(piw);
                            tempPrice.setPriceinitweight(pInitWeight);
                        }
                    } else {
                        // 第五列，续重价格
                        String pow = cellValue;
                        if (StringUtils.isEmpty(pow)) {
                            // 如果表格的值为空
                            rowMessage += "续重价格不能为空";
                        } else if (!ExpressUtils.isNumeric(pow) || pow.length() > 4) {
                            // 如果只不是数字或者位数大于4为
                            rowMessage += "续重价格必须是4位正整数";
                        } else {
                            pOverWeight = new BigDecimal(pow);
                            tempPrice.setPriceoverweight(pOverWeight);
                        }
                    }
                } else {
                    rowMessage += "第" + (c + 1) + "列数据为空，请仔细检查；";
                    //检测到这一行的cell为空，转向读取下一行
                    break;
                }
            }
            //拼接每行的错误提示
            if (!StringUtils.isEmpty(rowMessage)) {
                errorMsg += br + "第" + (r + 1) + "行，" + rowMessage;
            } else {
                // 如果此行数据没有问题，加入缓存列表
                pricesList.add(tempPrice);
            }
        }

        //校验后删除上传的临时文件
        if (tempFile.exists()) {
            tempFile.delete();
        }

        // 检查Excel表中的数据是否有冲突，也就是说是否存在同一家公司的收件的是否一样,一样则会返回错误信息
        errorMsg += ExpressUtils.checkExcell(pricesList);

        if (!errorMsg.isEmpty()) {
            // 如果有错误信息，抛出异常
            errorMsg = "导入失败!" + errorMsg;
            throw new ImportException(errorMsg);
        }

        //全部验证通过才导入到数据库
        for (Price price : pricesList) {
            priceMapper.insertSelective(price);
        }
        errorMsg = "导入成功!" + br + "共导入" + pricesList.size() + "条记录.";
        return errorMsg;
    }
}
